package org.jeecg.modules.system.service.impl;

import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Lists;
import io.micrometer.core.instrument.Meter;
import io.netty.util.internal.StringUtil;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SsoUtil;
import org.jeecg.common.util.StringUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.mapper.SysUserRoleMapper;
import org.jeecg.modules.system.service.ISysRoleService;
import org.jeecg.modules.system.service.ISysUserRoleService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.vo.SysUserRoleScope;
import org.jeecg.modules.system.vo.SysUserRoleScopeResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * <p>
 * 用户角色表 服务实现类
 * </p>
 *
 * @Author scott
 * @since 2018-12-21
 */
@Service
public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleMapper, SysUserRole> implements ISysUserRoleService {

	@Autowired
	private ISysUserService userService;
	@Autowired
	private ISysRoleService roleService;
	@Autowired
	private SysUserRoleMapper sysUserRoleMapper;
	
	/**
	 * 查询所有用户对应的角色信息
	 */
	@Override
	public Map<String,String> queryUserRole() {
		List<SysUserRole> uRoleList = this.list();
		List<SysUser> userList = userService.list();
		List<SysRole> roleList = roleService.list();
		Map<String,String> map = new IdentityHashMap<>();
		String userId = "";
		String roleId = "";
		String roleName = "";
		if(uRoleList != null && uRoleList.size() > 0) {
			for(SysUserRole uRole : uRoleList) {
				roleId = uRole.getRoleId();
				for(SysUser user : userList) {
					userId = user.getId();
					if(uRole.getUserId().equals(userId)) {
						roleName = this.searchByRoleId(roleList,roleId);
						map.put(userId, roleName);
					}
				}
			}
			return map;
		}
		return map;
	}
	
	/**
	 * queryUserRole调用的方法
	 * @param roleList
	 * @param roleId
	 * @return
	 */
	private String searchByRoleId(List<SysRole> roleList, String roleId) {
		while(true) {
			for(SysRole role : roleList) {
				if(roleId.equals(role.getId())) {
					return role.getRoleName();
				}
			}
		}
	}
	/**
	 * 新增用户角色作用域权限
	 * @param sysUserRoleScope
	 */
	@Override
	public void addUserRoleScope(SysUserRoleScope sysUserRoleScope) {
		List<String> roleIds = Arrays.asList(sysUserRoleScope.getRoleIds().split(","));
		List<String> scopeIds = Arrays.asList(sysUserRoleScope.getScopeIds().split(","));
		//编辑前已拥有的角色
		List<String> roleExistList = Arrays.asList(sysUserRoleScope.getRoleExistIds().split(","));
		Map<String,String> roleExistMap = new HashMap<>();
		for (String str:roleExistList){
			roleExistMap.put(str,"-");
		}
		//需要差分的角色
		List<String> diffRoleIdList = new ArrayList<>();
		List<SysUserRole> list = new ArrayList<SysUserRole>();
		for (String roleId:roleIds){
			if (StringUtils.isBlank(roleId)) continue;
			if (roleExistMap.get(roleId) != null){
				diffRoleIdList.add(roleId);
			}
			for (String scopeId:scopeIds){
				if (StringUtils.isBlank(scopeId)) continue;
				SysUserRole sysUserRoleAdd = new SysUserRole(String.valueOf(IdWorker.getId()),sysUserRoleScope.getUserId(),roleId,scopeId, SsoUtil.getLoginUser().getId());
				list.add(sysUserRoleAdd);
			}
		}
		List<SysUserRole> diffRoleList = new ArrayList<>();
		if (diffRoleIdList.size() > 0){
			LambdaQueryWrapper<SysUserRole> query = new LambdaQueryWrapper<SysUserRole>();
			query.eq(SysUserRole::getUserId, sysUserRoleScope.getUserId());
			query.in(SysUserRole::getRoleId,diffRoleIdList);
			diffRoleList = this.list(query);
			this.remove(query);
		}
		if (list.size() > 0 ){
			sysUserRoleMapper.insertBatch(list);
		}
		//将删除的内容 插入到历史记录表中
		for (SysUserRole addHis:diffRoleList){
			addHis.setUpdateBy(SsoUtil.getLoginUser().getId());
			addHis.setUpdateTime(new Date());
		}
		if (diffRoleList.size() > 0){
			sysUserRoleMapper.insertBatchHis(diffRoleList);
		}
	}


	/**
	 * 编辑用户角色作用域权限
	 * @param sysUserRoleScope
	 */
	@Override
	public void editUserRoleScope(SysUserRoleScope sysUserRoleScope) {
		//判断需要增加的作用域
		List<String> addScopeIdList = Arrays.asList(sysUserRoleScope.getScopeIds().split(","));
		List<String> diffScopeIdList = getDiff(sysUserRoleScope.getLastScopeIds(),sysUserRoleScope.getScopeIds());
		//需要删除的作用域
		List<String> delScopeIdList = getDiff(sysUserRoleScope.getScopeIds(),sysUserRoleScope.getLastScopeIds());
		//编辑前已拥有的角色
		List<String> roleExistList = Arrays.asList(sysUserRoleScope.getRoleExistIds().split(","));
		Map<String,String> roleExistMap = new HashMap<>();
		for (String str:roleExistList){
			roleExistMap.put(str,"-");
		}
		//当前选中的所有角色
		List<String> roleIdList = Arrays.asList(sysUserRoleScope.getRoleIds().split(","));
		//需要增加的角色  在已存在的角色列表里没有的
		List<String> addRoleIdList = getDiff(sysUserRoleScope.getRoleExistIds(),sysUserRoleScope.getRoleIds());
		//需要删除的角色 - 此处的删除指的是 删除当前主表里的角色信息 移动到历史表中 属于半差分
		List<String> delRoleIdList = new ArrayList<>();
		for (String str:roleIdList){
			if (roleExistMap.containsKey(str) && !str.equals(sysUserRoleScope.getLastRoleId())){
				delRoleIdList.add(str);
				addRoleIdList.add(str);
			}
		}
		//添加角色
		List<SysUserRole> addUserRoleList = new ArrayList<>();
		//收集需要删除的角色信息
		List<SysUserRole> delRoleList = new ArrayList<>();
		if (delRoleIdList.size() > 0 ){
			LambdaQueryWrapper<SysUserRole> query = new LambdaQueryWrapper<SysUserRole>();
			query.eq(SysUserRole::getUserId, sysUserRoleScope.getUserId());
			query.in(SysUserRole::getRoleId,delRoleIdList);
			delRoleList = this.list(query);
			this.remove(query);//执行删除操作
		}
		//收集需要更新的角色信息  - 就是当前选中编辑的这个角色
		//删除角色对应的作用域
		if (delScopeIdList.size() > 0){
			LambdaQueryWrapper<SysUserRole> query = new LambdaQueryWrapper<SysUserRole>();
			query.eq(SysUserRole::getUserId, sysUserRoleScope.getUserId());
			query.eq(SysUserRole::getRoleId,sysUserRoleScope.getLastRoleId());
			query.in(SysUserRole::getScopeId,delScopeIdList);
			List<SysUserRole> diffList = this.list(query);
			delRoleList.addAll(diffList);
			this.remove(query);//执行删除操作
		}
		//将删除的内容 插入到历史记录表中
		for (SysUserRole addHis:delRoleList){
			addHis.setUpdateBy(SsoUtil.getLoginUser().getId());
			addHis.setUpdateTime(new Date());
		}
		if (delRoleList.size() > 0){
			sysUserRoleMapper.insertBatchHis(delRoleList);
		}
		for (String diff:diffScopeIdList){
//			SysUserRole diffRoleScope = new SysUserRole(null,sysUserRoleScope.getUserId(),sysUserRoleScope.getLastRoleId(),SsoUtil.getLoginUser().getId(),diff);
			SysUserRole diffRoleScope = new SysUserRole();
			diffRoleScope.setUserId(sysUserRoleScope.getUserId());
			diffRoleScope.setRoleId(sysUserRoleScope.getLastRoleId());
			diffRoleScope.setScopeId(diff);
			addUserRoleList.add(diffRoleScope);
		}
		for (String role:addRoleIdList){
			for (String scope:addScopeIdList){
				SysUserRole addRoleScope = new SysUserRole(String.valueOf(IdWorker.getId()),sysUserRoleScope.getUserId(),role,scope,SsoUtil.getLoginUser().getId());
				addUserRoleList.add(addRoleScope);
			}
		}
		if (addUserRoleList.size() > 0 ){
			sysUserRoleMapper.insertBatch(addUserRoleList);
		}
	}

	@Override
	public void insertBatchHis(List<SysUserRole> list) {
		sysUserRoleMapper.insertBatchHis(list);
	}

	@Override
	public List<String> queryProjectIds(BaseEntity baseEntity) {
		LoginUser user = SsoUtil.getLoginUser();
		List<SysDepart>  projectList =  sysUserRoleMapper.queryProjectList(baseEntity.getMenuPath(),user.getId(),baseEntity.getDepartType(),baseEntity.getDepartIdEx());
		List<String> projectIds = new ArrayList<>();
		for (SysDepart sysDepart:projectList){
			projectIds.add(sysDepart.getId());
		}
		if (projectIds.size() == 0) {
			projectIds.add("");
		}
		return projectIds;
	}

    @Override
    public List<String> queryCompanyIds(BaseEntity baseEntity) {
        LoginUser user = SsoUtil.getLoginUser();
        List<SysDepart>  projectList =  sysUserRoleMapper.queryDepartTreeList(baseEntity.getMenuPath(),user.getId(),baseEntity.getDepartType(),baseEntity.getDepartIdEx());
        List<String> companyIds = new ArrayList<>();
        for (SysDepart depart:projectList){
            if (CommonConstant.DEPART_PROPERTY_COMPANY.equals(depart.getType())){
                companyIds.add(depart.getId());
            }
        }
        return companyIds;
    }

	@Override
	public List<String> queryOfficeIds(BaseEntity baseEntity) {
		LoginUser user = SsoUtil.getLoginUser();
		List<SysDepart>  projectList =  sysUserRoleMapper.queryDepartTreeList(baseEntity.getMenuPath(),user.getId(),baseEntity.getDepartType(),baseEntity.getDepartIdEx());
		List<String> officeIds = new ArrayList<>();
		for (SysDepart depart:projectList){
			if (CommonConstant.DEPART_PROPERTY_OFFICE.equals(depart.getType())){
				officeIds.add(depart.getId());
			}
		}
		return officeIds;
	}

	@Override
	public List<String> queryDepartIds(BaseEntity baseEntity) {
		LoginUser user = SsoUtil.getLoginUser();
		List<SysDepart>  projectList =  sysUserRoleMapper.queryDepartTreeList(baseEntity.getMenuPath(),user.getId(),baseEntity.getDepartType(),baseEntity.getDepartIdEx());
		List<String> departIds = new ArrayList<>();
		for (SysDepart depart:projectList){
			if (CommonConstant.DEPART_PROPERTY_DEPARTMENT.equals(depart.getType())){
				departIds.add(depart.getId());
			}
		}
		return departIds;
	}

	@Override
	public List<SysDepart> queryDepartTreeList(String menuPath, String userId,String departProperty) {
		List<SysDepart> list = sysUserRoleMapper.queryDepartTreeList(menuPath,userId,null,null);
		List<SysDepart> returnList = new ArrayList<>();
		if (list != null && list.size() > 0 && StringUtils.isNotBlank(departProperty)){
			if (CommonConstant.DEPART_WHERE_CO.equals(departProperty)){
				for (SysDepart depart:list){
					if (CommonConstant.DEPART_PROPERTY_COMPANY.equals(depart.getType()) || CommonConstant.DEPART_PROPERTY_OFFICE.equals(depart.getType())){
						returnList.add(depart);
					}
				}
				return returnList;
			} else if (CommonConstant.DEPART_WHERE_O.equals(departProperty)){
				for (SysDepart depart:list){
					if (CommonConstant.DEPART_PROPERTY_OFFICE.equals(depart.getType())){
						returnList.add(depart);
					}
				}
				return returnList;
			}
		}
		return list;
	}



	@Override
	public List<SysDepart> queryDepartTreeListByKeywords(String keyword,String menuPath, String userId,String departProperty) {
		List<SysDepart> list = sysUserRoleMapper.queryDepartTreeListByKeywords(keyword,menuPath,userId,null,null);
		List<SysDepart> returnList = new ArrayList<>();
		if (list != null && list.size() > 0 && StringUtils.isNotBlank(departProperty)){
			if (CommonConstant.DEPART_WHERE_CO.equals(departProperty)){
				for (SysDepart depart:list){
					if (CommonConstant.DEPART_PROPERTY_COMPANY.equals(depart.getType()) || CommonConstant.DEPART_PROPERTY_OFFICE.equals(depart.getType())){
						returnList.add(depart);
					}
				}
				return returnList;
			} else if (CommonConstant.DEPART_WHERE_O.equals(departProperty)){
				for (SysDepart depart:list){
					if (CommonConstant.DEPART_PROPERTY_OFFICE.equals(depart.getType())){
						returnList.add(depart);
					}
				}
				return returnList;
			}
		}
		return list;
	}

	@Override
	public List<SysDepart> queryProjectTreeListByDepartId(List<String> departIdList) {
		return sysUserRoleMapper.queryProjectTreeListByDepartId(departIdList);
	}

	@Override
	public List<SysPermission> queryUserPermission(String userId,String tenantId,String client) {
		return sysUserRoleMapper.queryUserPermission(userId,tenantId,client);
	}

	@Override
	public List<SysUserRole> selectByMainId(String mainId) {
		return sysUserRoleMapper.selectByMainId(mainId);
	}
	@Override
	public List<SysUserRole> selectServerByMainId(String mainId,String tenantId) {
		return sysUserRoleMapper.selectServerByMainId(mainId,tenantId);
	}


	@Override
	public String dataScopeDepartOnlyFilter(LoginUser user, String departAlias, String menuPath,String userAlias,String departIdEx) {
		StringBuilder sqlString = new StringBuilder();
		// 进行权限过滤，多个角色权限范围之间为或者关系。
		List<String> dataScope = Lists.newArrayList();
		List<SysDepart> departList = Lists.newArrayList();
		if (StringUtils.isNotBlank(departIdEx)){
			 departList = sysUserRoleMapper.queryDepartTreeList(menuPath, user.getId(),"c",departIdEx);
		} else {
			// 超级管理员，跳过权限过滤
			if (!user.isAdmin()) {
				 departList = sysUserRoleMapper.queryDepartTreeList(menuPath, user.getId(), null, null);
			}
		}
		if (departList.size() > 0 ){
			renderData(departAlias, sqlString, departList);
		}
		/*if (StringUtils.isNotBlank(userAlias)){ //设置了用户别名，则当前权限为本人；
			for (String ua : StringUtils.split(userAlias, ",")){
				sqlString.append(" OR " + ua + ".id = '" + user.getId() + "'");
			}
		}*/
		if (StringUtils.isNotBlank(sqlString.toString())){
			return sqlString.toString();
		}
		return "";
	}
	@Override
	public String dataScopeProjectOnlyFilter(LoginUser user, String projectAlias, String menuPath,String userAlias,String departIdEx) {
		StringBuilder sqlString = new StringBuilder();
		// 进行权限过滤，多个角色权限范围之间为或者关系。
		List<String> dataScope = Lists.newArrayList();
		String departs = dataScopeDepartOnlyFilter(user,"",menuPath,userAlias,departIdEx);
		if (StringUtils.isNotBlank(departs) && !departs.trim().equals("''")){
			List<SysDepart> projectList = queryProjectTreeListByDepartId(Arrays.asList(departs.split(",")));
			renderData(projectAlias, sqlString, projectList);
		}
		if (StringUtils.isNotBlank(sqlString.toString())){
			return sqlString.toString();
		}
		return "";
	}

	@Override
	public List<SysUserRole> queryServerByUserId(String tenantId, String userId) {
		return sysUserRoleMapper.queryServerByUserId(tenantId,userId);
	}

	@Override
	public void editServerUserRoleScope(SysUserRoleScope sysUserRoleScope) {
		if (StringUtils.isBlank(sysUserRoleScope.getRoleIds())) return;
		List<String> roleIds = Arrays.asList(sysUserRoleScope.getRoleIds().split(","));
		sysUserRoleScope.setRoleIdsList(roleIds);
		List<String> scopeIds = Arrays.asList(sysUserRoleScope.getScopeIds().split(","));
		//删除旧的数据
		sysUserRoleMapper.delServerUserRoleScope(sysUserRoleScope);
		//添加新的数据
		List<SysUserRole> addUserRoleList = new ArrayList<>();
		for (String role:roleIds){
			if (StringUtils.isBlank(role)) continue;
			for (String scope:scopeIds){
				SysUserRole addRoleScope = new SysUserRole();
				addRoleScope.setId(String.valueOf(IdWorker.getId()));
				addRoleScope.setUserId(sysUserRoleScope.getUserId());
				addRoleScope.setRoleId(role);
				addRoleScope.setScopeId(scope);
				addRoleScope.setTenantId(sysUserRoleScope.getTenantId());
				addRoleScope.setCreateBy(SsoUtil.getLoginUser().getId());
				addRoleScope.setCreateTime(new Date());
				addUserRoleList.add(addRoleScope);
			}
		}
		if (addUserRoleList.size() > 0 ){
			sysUserRoleMapper.insertServerBatch(addUserRoleList);
		}
	}

	@Override
	public void serverSave(SysUserRole sysUserRole) {
		String userId = SsoUtil.getLoginUser().getId();
		sysUserRole.setId(String.valueOf(IdWorker.getId()));
		sysUserRole.setCreateBy(userId);
		sysUserRole.setCreateTime(new Date());
		sysUserRole.setUpdateBy(userId);
		sysUserRole.setUpdateTime(new Date());
		sysUserRoleMapper.serverSave(sysUserRole);
	}

	private void renderData(String projectAlias, StringBuilder sqlString, List<SysDepart> projectList) {
		if (StringUtils.isNotBlank(projectAlias)){
            sqlString.append(" AND " + projectAlias + ".id IN ( ");
            if (projectList.size() > 0 ){
                for (int i=0; i<projectList.size();i++){
                    sqlString.append("'" + projectList.get(i).getId() + "'");
                    if (i != projectList.size() -1){
                        sqlString.append(",");
                    }
                }
                sqlString.append(" ) ");
            } else {
                sqlString.append(" '' )");
            }
        } else {
            for (SysDepart depart:projectList){
                sqlString.append(depart.getId() + ",");
            }
        }
	}


	/**
	 * 从diff中找出main中没有的元素
	 * @param main
	 * @param diff
	 * @return
	 */
	private List<String> getDiff(String main, String diff){
		if(oConvertUtils.isEmpty(diff)) {
			return null;
		}
		if(oConvertUtils.isEmpty(main)) {
			return Arrays.asList(diff.split(","));
		}
		String[] mainArr = main.split(",");
		String[] diffArr = diff.split(",");
		Map<String, Integer> map = new HashMap<>();
		for (String string : mainArr) {
			map.put(string, 1);
		}
		List<String> res = new ArrayList<String>();
		for (String key : diffArr) {
			if(oConvertUtils.isNotEmpty(key) && !map.containsKey(key)) {
				res.add(key);
			}
		}
		return res;
	}

}
